package czy.demo.entity;


import com.fasterxml.jackson.annotation.JsonIgnore;
import czy.demo.entity.BaseEntity;
import czy.demo.entity.Permission;
import czy.demo.entity.Role;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Entity
@Table(name = "sys_user")
public class User extends BaseEntity implements UserDetails{

    /* id */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    /* 用户名 */
    @Column(unique = true)
    private String username;

    /* 密码哈希 */
    private String password;

    /* 用户描述 */
    private String description;

    /* 用户是否过期，如果为true，则认证时会抛出过期异常 */
    private Boolean expired;

    /* 用户是否锁定，如果为true，则认证时会抛出锁定异常 */
    private Boolean locked;

    /* 证书是否过期，如果为rtue，则认证时会抛出证书过期异常 */
    private Boolean credentialsExpired;

    /* 用户是否启用，如果为false，则认证时会抛出禁用异常 */
    private Boolean enabled;

    /* 用户角色列表 */
    @ManyToMany(targetEntity = Role.class,fetch = FetchType.LAZY)
    @JoinTable(
            name = "sys_user_role",
            joinColumns = @JoinColumn(name = "user_id",referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "role_id",referencedColumnName = "id"),
            uniqueConstraints = @UniqueConstraint(name = "unique_user_role", columnNames = {"user_id","role_id"})
    )
    private List<Role> roles = new ArrayList<>();

    public User(){}

    public User(Integer id,String username, String password, String description,Boolean expired, Boolean locked, Boolean credentialsExpired, Boolean enabled, List<Role> roles) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.description = description;
        this.expired = expired;
        this.locked = locked;
        this.credentialsExpired = credentialsExpired;
        this.enabled = enabled;
        this.roles = roles;
    }

    /* 获取用户关联权限方法，安全框架使用，复合字段不能序列化 */
    @Override
    @JsonIgnore
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.roles.stream()
                /* 过滤启用角色 */
                .filter(Role::getEnabled)
                /* 获取角色权限列表 */
                .map(Role::getPermissions)
                /* 扁平化权限流 */
                .flatMap(List::stream)
                /* 去重 */
                .distinct()
                /* 过滤出启用权限 */
                .filter(Permission::getEnabled)
                /* 收集 */
                .collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    @JsonIgnore
    public boolean isAccountNonExpired() {
        return !expired;
    }

    @Override
    @JsonIgnore
    public boolean isAccountNonLocked() {
        return !locked;
    }

    @Override
    @JsonIgnore
    public boolean isCredentialsNonExpired() {
        return !credentialsExpired;
    }

    /* boolean类型属性默认的getter方法为is开头 */
    @Override
    public boolean isEnabled() {
        return enabled;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Boolean getExpired() {
        return expired;
    }

    public void setExpired(Boolean expired) {
        this.expired = expired;
    }

    public Boolean getLocked() {
        return locked;
    }

    public void setLocked(Boolean locked) {
        this.locked = locked;
    }

    public Boolean getCredentialsExpired() {
        return credentialsExpired;
    }

    public void setCredentialsExpired(Boolean credentialsExpired) {
        this.credentialsExpired = credentialsExpired;
    }

    public Boolean getEnabled() {
        return enabled;
    }

    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }

    /* hibernate 使用内部集合org.hibernate.collection.internal
     * 这些集合依赖session，所以反序列化会报错
      * */
    public List<Role> getRoles() {
        return new ArrayList<>(roles);
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

}
